#include <cctype>
#include <cerrno>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <ctime>

#include <fcntl.h>
#include <new>
#include <sys/stat.h>
#include <sys/types.h>

#include "util.h"

#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

const int util_stdin = 0;
const int util_stdout = 1;
const int util_stderr = 2;

const int util_rdonly = O_RDONLY;
const int util_wronly = O_WRONLY;
const int util_creat = O_CREAT;
const int util_trunc = O_TRUNC;
const int util_append = O_APPEND;

int util_printf(const char * _format, ...) {
		va_list ap;
		va_start(ap, _format);
		int rec = vprintf(_format, ap);
		va_end(ap);

		return rec;
}

static inline int util_ascii_to_hex(int _h) throw() {
		if( _h >= 'a' && _h <= 'f' )
				return _h - 'a' + 10;

		else if( _h >= 'A' && _h <= 'F' )
				return _h - 'A' + 10;
		
		else if( _h >= '0' && _h <= '9' )
				return _h - '0';
		else
				return 0xf;
}

size_t util_dehttpize(char* _d, size_t _s) throw() {
		size_t i = 0, t = 0;

		while( i < _s ) {
				switch( _d[i] ) {
				case '%':
						if( i + 3 <= _s ) {
								_d[t] = (char)( (util_ascii_to_hex(_d[i + 1]) << 4) | util_ascii_to_hex(_d[i + 2]));
								i += 3;
						} else {
								_d[t] = _d[i];
								i += 1;
						}
						break;

				case '+':
						_d[t] = ' ';
						i += 1;
						break;

				default:
						_d[t] = _d[i];
						i += 1;
				}
				++t;
		}
		return t;
}

char* util_htmlize(const char *_in, size_t _size) throw() {
		size_t i, j;
		size_t count = 0;

		for(i = 0; i < _size; ++i) {
				switch( _in[i] ) {
				case '<':
						count += 4; 
						break;
				case '>':
						count += 4; 
						break;
				case '&':
						count += 5;
						break;
				case '"':
						count += 6;
						break;
				default:
						++count;
						break;
				}
		}
	
		char* out = new (std::nothrow) char[ count + 1 ];
		if( NULL == out )
				return NULL;

		i = 0;
		for(j = 0; j < _size; ++j) {
				switch( _in[j] ) {
				case '<':   
						out[i++] = '&';
						out[i++] = 'l';
						out[i++] = 't';
						out[i++] = ';';
						break;
				case '>':   
						out[i++] = '&';
						out[i++] = 'g';
						out[i++] = 't';
						out[i++] = ';';
						break;
				case '&':   
						out[i++] = '&';
						out[i++] = 'a';
						out[i++] = 'm';
						out[i++] = 'p';
						out[i++] = ';';
						break;
				case '"':   
						out[i++] = '&';
						out[i++] = 'q';
						out[i++] = 'u';
						out[i++] = 'o';
						out[i++] = 't';
						out[i++] = ';';
						break;
				default:
						out[i++] = _in[j];
						break;
				}
		}

		out[i] = '\0';
		
		return out;
}


int util_open(const char* _pn, int _f, mode_t _m) throw() {
#ifdef _WIN32
		return open(_pn, _f | O_BINARY, _m);
#else
		return open(_pn, _f, _m);
#endif
}

int util_close(int _d) throw() {
		int t;
		while( -1 == (t = close(_d)) && EINTR == errno );
		return t;
}

ssize_t util_readn(int _d, char* _b, size_t _cnt) throw() {
		size_t p = 0;
		ssize_t t;

		while( p < _cnt ) {
				while( -1 == (t = read(_d, _b + p, _cnt - p)) && EINTR == errno );

				if( -1 == t )
						return -1;				
				else if( 0 == t )
						return p;

				p += t;
		}
		
		return p;
}

ssize_t util_writen(int _d, const char* _b, size_t _cnt) throw() {
		size_t p = 0;
		ssize_t t;
		
		while( p < _cnt ) {
				while( -1 == (t = write(_d, _b + p, _cnt - p)) && EINTR == errno );

				if( -1 == t )
						return -1;

				p += t;
		}
		
		return p;
}

int util_access(const char* _pn, mode_t _m) throw() {
		return access(_pn, _m);
}

int util_stat(const char* _pn, struct stat *_st) throw() {
		return stat(_pn, _st);
}

int util_fstat(int _d, struct stat *_st) throw() {
		return fstat(_d, _st);
}

bool util_isdir(mode_t _m) throw() {
#ifdef _WIN32
		return 0 != (_m & _S_IFDIR);
#else
		return S_ISDIR(_m);
#endif //_WIN32
}

int util_setbinmode(int _fd) throw() {
#ifdef _WIN32
		return _setmode(_fd, _O_BINARY);
#else
		return 0;
#endif
}

time_t util_time() throw() {
		static time_t t = time(NULL);
		return t;
}

const char * util_ctime() throw() {
		static bool singleton = false;
		static char buf[26]; // At the start buf[] is {0, 0, 0, 0, 0, ...}.
		if( !singleton ) {
				singleton = true;
				time_t t = util_time();
				memcpy(buf, ctime(&t), 24);
		}
		return buf;
}

bool util_isspace(char _c) throw() {
		return 0 != isspace((unsigned char)_c);
}

bool util_isalpha(char _c) throw() {
		return 0 != isalpha((unsigned char)_c);
}

bool util_isdigit(char _c) throw() {
		return 0 != isdigit((unsigned char)_c);
}

